﻿using System.Reflection.Metadata.Ecma335;
using AutoTest.Business.IServices.Common;
using AutoTest.Business.Options;
using AutoTest.Business.Vo.AdminUser;
using AutoTest.Business.Vo.UserInfo;
using AutoTest.Common;
using AutoTest.Common.Extension;
using AutoTest.Domain;
using AutoTest.Domain.Entities;
using AutoTest.Domain.Enums;
using AutoTest.Framework.Ioc;
using JWT;
using JWT.Algorithms;
using JWT.Builder;
using JWT.Exceptions;
using JWT.Serializers;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;

namespace AutoTest.Business.Services.Common
{
    /// <summary>
    /// Jwt服务
    /// </summary>
    public class JwtService(ISettingService settingService,ISqlSugarClient db) : IJwtService, IScoped
    {
        private readonly JwtOption _jwtOption = settingService.GetSettingOptionAsync<JwtOption>(AppConsts.APPSETTING_JWT).GetAwaiter().GetResult();
        private readonly ISqlSugarClient _db = db;

        /// <summary>
        /// 前台用户生成token
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NullReferenceException"></exception>
        public string Generate(LoginUserVo userInfo)
        {
            var creator = JwtBuilder.Create().WithAlgorithm(new HMACSHA256Algorithm())
                .WithJsonSerializer(new JsonNetSerializer())
                .WithUrlEncoder(new JwtBase64UrlEncoder())
                .Audience(_jwtOption.Audience)
                .Issuer(_jwtOption.Issuer)
                .WithSecret(_jwtOption.SecurityKey)
                .ExpirationTime(DateTime.Now.AddMinutes(_jwtOption.ExpireMinutes))
                .AddClaim("UserId", userInfo.Id.ToString())
                .AddClaim("UserName", userInfo.NickName)
                .AddClaim("UserInfo", userInfo.ToJson().ToBase64());

            var token = creator.Encode();

            return token;
        }
        /// <summary>
        /// 后台管理员用户计算token
        /// </summary>
        /// <param name="adminUserInfo"></param>
        /// <returns></returns>
        public string Generate(AdminLoginVo adminUserInfo)
        {
            var creator = JwtBuilder.Create().WithAlgorithm(new HMACSHA256Algorithm())
               .WithJsonSerializer(new JsonNetSerializer())
               .WithUrlEncoder(new JwtBase64UrlEncoder())
               .Audience(_jwtOption.Audience)
               .Issuer(_jwtOption.Issuer)
               .WithSecret(_jwtOption.SecurityKey)
               .ExpirationTime(DateTime.Now.AddMinutes(_jwtOption.ExpireMinutes))
               .AddClaim("UserId", adminUserInfo.Id.ToString())
               .AddClaim("UserName", adminUserInfo.UserName)
               .AddClaim("UserInfo", adminUserInfo.ToJson().ToBase64());

            var token = creator.Encode();

            return token;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="token"></param>
        /// <param name="errorMsg"></param>
        /// <returns></returns>
        public LoginUserVo GetLoginUserVoByToken(string token,out string errorMsg)
        {
            errorMsg = string.Empty;
            LoginUserVo userInfo = null!;
            if (token.StartsWith(AppConsts.AUTHORIZATION_JWT_PREFIX, StringComparison.OrdinalIgnoreCase))
            {
                token = token.Replace(AppConsts.AUTHORIZATION_JWT_PREFIX, "", StringComparison.OrdinalIgnoreCase).Trim();
            }
           
            try
            {
                var decoder = JwtBuilder.Create().WithAlgorithm(new HMACSHA256Algorithm())
                       .WithJsonSerializer(new JsonNetSerializer())
                       .WithUrlEncoder(new JwtBase64UrlEncoder())
                       .Audience(_jwtOption.Audience)
                       .Issuer(_jwtOption.Issuer)
                       .WithSecret(_jwtOption.SecurityKey);
                var dict = decoder.Decode<Dictionary<string, object>>(token);
                userInfo = (dict["UserInfo"]?.ToString() ?? "").DesBase64().DeserializeJson<LoginUserVo>()!;
                if (userInfo != null)
                {
                    var entity = _db.Queryable<UserInfo>().First(t => t.Id == userInfo.Id && t.Status == EnumStatus.Enable);
                    if (entity == null) userInfo = null!;
                }
              
            }
            catch (TokenExpiredException)
            {
                //表示过期
                errorMsg = "expired";
            }
            catch (SignatureVerificationException)
            {
                //表示验证不通过
                errorMsg = "invalid";
            }
            catch (Exception)
            {
                errorMsg = "error";
            }

            return userInfo!;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="token"></param>
        /// <param name="errorMsg"></param>
        /// <returns></returns>
        public AdminLoginVo GetAdminLoginUserVoByToken(string token, out string errorMsg)
        {
            errorMsg = string.Empty;
            AdminLoginVo userInfo = null!;
            if (token.StartsWith(AppConsts.AUTHORIZATION_JWT_PREFIX, StringComparison.OrdinalIgnoreCase))
            {
                token = token.Replace(AppConsts.AUTHORIZATION_JWT_PREFIX, "", StringComparison.OrdinalIgnoreCase).Trim();
            }

            try
            {
                var decoder = JwtBuilder.Create().WithAlgorithm(new HMACSHA256Algorithm())
                       .WithJsonSerializer(new JsonNetSerializer())
                       .WithUrlEncoder(new JwtBase64UrlEncoder())
                       .Audience(_jwtOption.Audience)
                       .Issuer(_jwtOption.Issuer)
                       .WithSecret(_jwtOption.SecurityKey);
                var dict = decoder.Decode<Dictionary<string, object>>(token);
                userInfo = (dict["UserInfo"]?.ToString() ?? "").DesBase64().DeserializeJson<AdminLoginVo>()!;
            }
            catch (TokenExpiredException)
            {
                //表示过期
                errorMsg = "expired";
            }
            catch (SignatureVerificationException)
            {
                //表示验证不通过
                errorMsg = "invalid";
            }
            catch (Exception)
            {
                errorMsg = "error";
            }

            return userInfo;
        }
        /// <summary>
        /// 校验解析token
        /// </summary>
        /// <returns></returns>
        public bool ValidateJwtToken(string token,out string msg)
        {
            msg = "";
            bool flag = false;
            try
            {
                var decoder = JwtBuilder.Create().WithAlgorithm(new HMACSHA256Algorithm())
                 .WithJsonSerializer(new JsonNetSerializer())
                 .WithUrlEncoder(new JwtBase64UrlEncoder())
                 .Audience(_jwtOption.Audience)
                 .Issuer(_jwtOption.Issuer)
                 .WithSecret(_jwtOption.SecurityKey).Decode<Dictionary<string, object>>(token);
                flag = true;
            }
            catch (TokenExpiredException)
            {
                //表示过期
                msg = "expired";
            }
            catch (SignatureVerificationException)
            {
                //表示验证不通过
                msg = "invalid";
            }
            catch (Exception)
            {
                msg = "error";
            }
            return flag;
        }

        /// <summary>
        /// 获取当前登录人
        /// </summary>
        /// <returns></returns>
        public LoginUserVo? GetCurrentUser()
        {
            var httpContextAccessor = ServiceLocator.ServiceProvider?.GetService<IHttpContextAccessor>();
            var token = httpContextAccessor?.HttpContext?.Request.Headers.Authorization.FirstOrDefault()?.ToString() ?? "";

            if (token.IsNotEmpty()) return GetLoginUserVoByToken(token, out _);
            return null;
        }

        /// <summary>
        /// 获取后台管理员用户
        /// </summary>
        /// <returns></returns>
        public AdminLoginVo? GetCurrentAdminUser()
        {
            var httpContextAccessor = ServiceLocator.ServiceProvider?.GetService<IHttpContextAccessor>();
            var token = httpContextAccessor?.HttpContext?.Request.Headers.Authorization.FirstOrDefault()?.ToString() ?? "";

            if (token.IsNotEmpty()) return GetAdminLoginUserVoByToken(token, out _);
            return null;
        }
    }
}
